/**
 * @file date-range
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from 'react';
import {findDOMNode} from 'react-dom';
import * as cx from 'classnames';
import './rich-text.scss';
import Editor from './react-monaco';
import * as assign from 'object-assign';
import * as debounce from 'lodash/debounce';
import {resizeSensor} from '../../util/resize-sensor';

function noJsExt(raw) {
  return raw.replace(/\.js$/, '');
}

const requireConfig = {
  url: __uri('/client/node_modules/monaco-editor/min/vs/loader.js'),
  paths: {
    'vs': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/editor.main.js')),
    'vs/base/worker/workerMain': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/base/worker/workerMain.js')),


    'vs/basic-languages/src/css': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/basic-languages/src/css')),
    'vs/basic-languages/src/sql': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/basic-languages/src/sql')),
    'vs/basic-languages/src/yaml': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/basic-languages/src/yaml')),

    'vs/editor/editor.main': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/editor.main.js')),
    'vs/basic-languages/src/markdown': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/basic-languages/src/markdown.js ')),
    'vs/editor/editor.main.css': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/editor.main.css')),
    'vs/editor/editor.main.nls': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/editor.main.nls.js')),
    'vs/editor/editor.main.nls.zh-cn': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/editor.main.nls.zh-cn.js')),

    'vs/editor/contrib/suggest/browser/String_16x.svg': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/contrib/suggest/browser/String_16x.svg')),
    'vs/editor/contrib/quickOpen/browser/symbol-sprite.svg': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/editor/contrib/quickOpen/browser/symbol-sprite.svg')),

    'vs/language/typescript/src/mode': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/typescript/src/mode.js')),
    'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/typescript/lib/typescriptServices.js')),
    'vs/language/typescript/src/worker': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/typescript/src/worker.js')),

    'vs/language/json/jsonMode': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/json/jsonMode.js')),
    'vs/language/json/jsonWorker': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/json/jsonWorker.js')),

    'vs/language/css/cssMode': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/css/cssMode.js')),
    'vs/language/css/cssWorker': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/language/css/cssWorker.js'))
  },

  'vs/nls' : {
    availableLanguages: {
      '*': 'zh-cn'
    }
  }
};

if (process.env.NODE_ENV === 'development') {
  requireConfig.paths = {
    'vs': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/editor.main.js')),
    'vs/base/worker/workerMain': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/base/worker/workerMain.js')),


    'vs/basic-languages/src/css': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/basic-languages/src/css')),
    'vs/basic-languages/src/sql': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/basic-languages/src/sql')),
    'vs/basic-languages/src/yaml': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/basic-languages/src/yaml')),

    'vs/editor/editor.main': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/editor.main.js')),
    'vs/basic-languages/src/markdown': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/basic-languages/src/markdown.js ')),
    'vs/basic-languages/src/python': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/basic-languages/src/python.js ')),
    'vs/basic-languages/src/java': noJsExt(__uri('/client/node_modules/monaco-editor/min/vs/basic-languages/src/java.js ')),
    'vs/editor/editor.main.css': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/editor.main.css')),
    'vs/editor/editor.main.nls': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/editor.main.nls.js')),
    'vs/editor/editor.main.nls.zh-cn': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/editor.main.nls.zh-cn.js')),

    'vs/editor/contrib/suggest/browser/String_16x.svg': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/contrib/suggest/browser/String_16x.svg')),
    'vs/editor/contrib/quickOpen/browser/symbol-sprite.svg': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/editor/contrib/quickOpen/browser/symbol-sprite.svg')),

    'vs/language/typescript/src/mode': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/typescript/src/mode.js')),
    'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/typescript/lib/typescriptServices.js')),
    'vs/language/typescript/src/worker': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/typescript/src/worker.js')),

    'vs/language/json/jsonMode': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/json/jsonMode.js')),
    'vs/language/json/jsonWorker': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/json/jsonWorker.js')),

    'vs/language/css/cssMode': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/css/cssMode.js')),
    'vs/language/css/cssWorker': noJsExt(__uri('/client/node_modules/monaco-editor/dev/vs/language/css/cssWorker.js'))
  };
}

window.MonacoEnvironment = {
  getWorkerUrl: function(workerId, label) {
    return __uri('./worker-loader-proxy.js');
  }
};

export default class MonacoEditor extends PureComponent
{
  static propTypes = {
    className: PropTypes.string,
    onChange: PropTypes.func.isRequired,
    jsonSchema: PropTypes.arrayOf(PropTypes.object),
    validateSchema: PropTypes.bool
  };

  static defaultProps = {
    onChange: value => console.log(value),
    className: 'form-control vsc-editor-control ',
    width: '100%',
    height: '200px',
    mode: 'json',
    theme: 'vs',
    validateSchema: false,
    jsonSchema: [
      {
        uri: "http://amis.baidu.com/renderer-schema.json",
        schema: {
          type: "object",
          properties: {
          }
        }
      }
    ]
  };

  constructor(props) {
    super(props);

    this.state = {
      focused: false,
      ready: false
    };

    this.handleFocus = this.handleFocus.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.editorWillMount = this.editorWillMount.bind(this);
    this.refresh = this.refresh.bind(this);
    this.mounted = true;
  }

  componentDidMount() {
    this.initResizeSensor();
  }

  componentWillUnmount() {
    if (this.unWatchResize) this.unWatchResize();
    this.mounted = false;
  }

  initResizeSensor() {
    if (this.unWatchResize) this.unWatchResize();
    const dom = this.refs.container;
    dom && (this.unWatchResize = resizeSensor(dom, debounce(this.refresh, 250, {
      leading: false,
      trailing: true
    })));
  }

  handleFocus() {
    this.setState({
      focused: true
    });
  }

  handleBlur() {
    this.setState({
      focused: false
    });
  }

  refresh() {
    const editor = this.refs.editor;

    editor && editor.editor && editor.editor.layout();
  }

  editorWillMount(monaco) {
    if (!this.mounted) {
      return;
    }
    const jsonSchema = this.props.jsonSchema;
    const validateSchema = this.props.validateSchema;
    this.setState({
      ready: true
    });

    // validation settings
    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: true,
      noSyntaxValidation: true
    });

    // monaco.languages.typescript.javascriptDefaults.setCompilerOptions(assign({}, monaco.languages.typescript.javascriptDefaults.getCompilerOptions(), {
    //   jsx: monaco.languages.typescript.JsxEmit.React
    // }));
    //
    // monaco.languages.typescript.typescriptDefaults.setCompilerOptions(assign({}, monaco.languages.typescript.typescriptDefaults.getCompilerOptions(), {
    //   jsx: monaco.languages.typescript.JsxEmit.React
    // }));

    monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
      schemas: jsonSchema,
      validate: validateSchema
    });
  }


  render() {
    const {
      className,
      ideClassName,
      onChange,
      value,
      mode,
      editorOnly,
      width,
      height,
      theme,
      disabled
    } = this.props;
    const focused = this.state.focused;

    const options = {
      selectOnLineNumbers: true,
      scrollBeyondLastLine: false,
      readOnly: disabled,
      folding: true,
      minimap: {
        enabled: false
      }
    };

    let body = (
      <Editor
        ref="editor"
        className={ideClassName}
        onChange={onChange}
        value={value}
        width={width}
        height={height}
        disabled={disabled}
        requireConfig={requireConfig}
        language={({js: 'javascript', jsx: 'javascript'})[mode] || mode}
        options={options}
        onFocus={this.handleFocus}
        onBlur={this.handleBlur}
        editorWillMount={this.editorWillMount}
        theme={theme}
      />
    );

    if (editorOnly) {
      return (
        <div ref="container" className="pos-rlt w-full h-full">
          {this.state.ready ? null : (
            <div className="pos-abt w-full text-center m-t-lg">
              <i className="fa fa-spinner fa-spin fa-3x fa-fw" />
            </div>
          )}
          {body}
        </div>
      );
    }

    return (
      <div className={cx('vsc-editor-control', className, {
        focus: focused
      })}>
        {this.state.ready ? null : (
          <div className="text-center m-t-lg">
            <i className="fa fa-spinner fa-spin fa-3x fa-fw" />
          </div>
        )}
        {body}
      </div>
    );
  }
}
